﻿using System;
using System.Collections.Generic;

namespace 安检系统
{
    /// <summary>
    /// 简单串行号去重缓存：在过期时间窗口内，同一serial只算一次 线程安全：内部用lock保护
    /// </summary>
    public class SerialCache
    {
        private readonly int capacity;
        private readonly Queue<string> queue;
        private readonly Dictionary<string, DateTime> map; // serial -> last timestamp
        private readonly TimeSpan expireTime;
        private readonly object _lock = new object();

        /// <summary> capacity：最多缓存多少个不同serial（先进先出淘汰） expireSeconds：过期秒数（<=0 或 解析失败时用默认5秒） </summary>
        public SerialCache(int capacity = 5, int? expireSeconds = null)
        {
            // 1) 过期秒数优先用传入值；没传则从配置读；否则默认5
            int ttlSec;

            if (expireSeconds.HasValue && expireSeconds.Value > 0)
            {
                ttlSec = expireSeconds.Value;
            }
            else
            {
                // 配置可能为 null/空/非法，必须 TryParse
                string cfg = null;
                try { cfg = App.GetBaseInfo()?.RFIDResetTime; } catch { /* 忽略配置读取异常 */ }

                if (!int.TryParse(cfg, out ttlSec) || ttlSec <= 0)
                    ttlSec = 5; // 默认5秒
            }

            this.expireTime = TimeSpan.FromSeconds(ttlSec);

            // 2) 容量兜底
            this.capacity = capacity > 0 ? capacity : 5;

            this.queue = new Queue<string>(this.capacity);
            this.map = new Dictionary<string, DateTime>(StringComparer.Ordinal);
        }

        /// <summary>
        /// 插入serial；若已存在但未过期，则不插入；若已过期会刷新时间。
        /// </summary>
        public void Insert(string serial)
        {
            if (string.IsNullOrWhiteSpace(serial)) return;

            lock (_lock)
            {
                // 已存在且未过期，跳过
                if (map.TryGetValue(serial, out var last) && (DateTime.Now - last) <= expireTime)
                    return;

                // 如果已存在但过期，先移除（下方会统一入队/写入时间）
                if (map.ContainsKey(serial))
                    Remove_NoLock(serial);

                // 容量满则淘汰最老一个
                if (queue.Count >= capacity)
                {
                    var oldest = queue.Dequeue();
                    map.Remove(oldest);
                }

                queue.Enqueue(serial);
                map[serial] = DateTime.Now;
            }
        }

        /// <summary>
        /// 判断serial是否存在且未过期（存在但过期会被移除并返回false）
        /// </summary>
        public bool Contains(string serial)
        {
            if (string.IsNullOrWhiteSpace(serial)) return false;

            lock (_lock)
            {
                if (map.TryGetValue(serial, out var t))
                {
                    if ((DateTime.Now - t) <= expireTime)
                        return true;

                    // 过期：移除
                    Remove_NoLock(serial);
                    return false;
                }
                return false;
            }
        }

        /// <summary>
        /// 无锁移除（仅供内部在已获得lock时调用）
        /// </summary>
        private void Remove_NoLock(string serial)
        {
            if (!map.Remove(serial)) return;

            // Queue不能直接移除中间元素，重建
            if (queue.Count == 0) return;

            var newQ = new Queue<string>(queue.Count);
            foreach (var s in queue)
            {
                if (!string.Equals(s, serial, StringComparison.Ordinal))
                    newQ.Enqueue(s);
            }
            queue.Clear();
            foreach (var s in newQ) queue.Enqueue(s);
        }

        /// <summary>
        /// （调试用）打印当前缓存
        /// </summary>
        public void PrintCache()
        {
            lock (_lock)
            {
                Console.WriteLine("当前缓存：" + string.Join(", ", queue));
            }
        }
    }
}